import json
import copy
from typing import List
from typing import Union
from apis import api_routes
from sqlalchemy import desc
from sqlalchemy import and_
from flask import abort, g, request, jsonify
from models.users.roles import Roles as Rs
from models.users.users import Users as Us
from security.decoration import certification
from public.sidebar import sidebars
from public.contexts import context_logs


@api_routes.route("/roles", methods=["POST"])
@certification(auth=True, role="admin")
def func_roles_post_api():
    """
    添加角色API, 需要角色验证才能添加
    http://127.0.0.1:8080/api/roles
    Content-Type=application/json
    methods=["POST"]
    {
    "role":           string        ****    角色名字
    "describe":       string        ****    角色描述
    "sidebars"        list[json]    ****    数据格式： /api/sidebar GET 返回数据格式，属性不能少，只改allow值
    }
    :return:
        {'status': 40001, 'msg': "这个角色已经存在"}
        {'status': 40002, 'msg': "角色描述已经存在"}
        {'status': 200, "msg": "添加角色成功"}
     ---
    tags:
      - 角色管理
    """
    data: dict = request.get_json()
    role: str = data.get("role")
    describe: str = data.get("describe")
    sidebar: Union[List[dict], None] = data.get("sidebars")

    if not all([role, describe, sidebar]):
        abort(400)

    role0: Union[Rs, None] = g.session.query(Rs).filter(Rs.role == role).first()
    if role0 is not None:
        return jsonify({'status': 40001, 'msg': "这个角色已经存在"})

    role1: Union[Rs, None] = g.session.query(Rs).filter(Rs.describe == describe).first()
    if role1 is not None:
        return jsonify({'status': 40002, 'msg': "角色描述已经存在"})

    # 检查属性
    for index, itr in enumerate(sidebar):
        mark0: Union[str, None] = itr.get("mark")
        allow0: Union[bool, None] = itr.get("allow")

        if mark0 is None or isinstance(allow0, bool) is False:
            abort(400)

        children: Union[List[dict], None] = itr.get("children")
        if isinstance(children, List) is False:
            abort(400)
        else:
            for index1, itr1 in enumerate(children):
                mark1: Union[str, None] = itr1.get("mark")
                allow1: Union[bool, None] = itr1.get("allow")
                if mark1 is None or isinstance(allow1, bool) is False:
                    abort(400)

    marks: dict = {}
    mark_str = None
    for index2, itr2 in enumerate(sidebar):
        mark2: Union[str, None] = itr2.get("mark")
        allow2: Union[bool, None] = itr2.get("allow")
        children: List[dict] = itr2.get("children")
        if len(children) == 0 and allow2 is True:
            marks[mark2] = allow2
        else:
            for index22, itr22 in enumerate(children):
                mark22: str = itr22.get("mark")
                allow22: bool = itr22.get("allow")
                if allow22 is True:
                    marks[mark22] = allow22

    if len(marks) != 0:
        mark_str = json.dumps(marks)

    log_pram: dict = {
        "role": role,
        "describe": describe,
        "sidebars": mark_str
    }
    context_logs(name="添加角色", obsolescence=None, data=str(log_pram))

    g.session.add(Rs(role=role, describe=describe, sidebars=mark_str))
    g.session.commit()
    return jsonify({'status': 200, "msg": "添加角色成功"})


@api_routes.route("/roles", methods=["GET"])
@certification(auth=True, role=None)
def func_roles_get_api():
    """
    分页获取角色列表， 分页参数可以自定义, 有token都可以访问, 如果前端角色麻烦 size直接等于1000
    http://127.0.0.1:8080/api/roles
    Content-Type=application/x-www-form-urlencoded
    methods=["GET"]
    {
    "index"         int      ****  第几页，默认为1
    "size"          int      ****  每页数据多少, 默认每页10条数据
    }
    :return:
        {'status': 400, 'msg': '客户端发送请求异常'}
        {'status': 403, 'msg': "token无效或者未登录或没有权限"}
        {'status': 4000, 'msg': "已经存在此用户"}
        {'status': 200, 'msg': "添加账户成功", }
    ---
    tags:
      - 角色管理
    """
    index = request.args.get("index", default=1, type=int)
    size = request.args.get("size", default=10, type=int)

    condition, resp = False, []
    counts: int = g.session.query(Rs.id).count() or 0

    page = int((counts / size) + 1) if (counts / size) > int(counts / size) else int(counts / size)
    data: List[Rs] = g.session.query(Rs).order_by(desc(Rs.id)).offset((index - 1) * size).limit(size).all()

    for index0, role in enumerate(data):

        sidebar = copy.deepcopy(sidebars)
        if role.role == "admin":
            for index, itr in enumerate(sidebar):
                itr["allow"] = True
                children: List[dict] = itr.get("children")
                for index2, itr2 in enumerate(children):
                    itr2["allow"] = True
        else:
            db_sidebar: dict = json.loads(role.sidebars) if role.sidebars else {}
            for index, itr in enumerate(sidebar):
                mark = itr.get("mark")
                itr["allow"] = db_sidebar.get(mark) or False

                children: List[dict] = itr.get("children")
                for index2, itr2 in enumerate(children):
                    mark = itr2.get("mark")
                    itr2["allow"] = db_sidebar.get(mark) or False
                    if itr2["allow"] is True:
                        itr["allow"] = True

        temp: dict = json.loads(role.__repr__())
        del temp["sidebars"]
        temp["sidebars"] = sidebar
        resp.append(copy.deepcopy(temp))
        del temp
    return jsonify({'status': 200, 'data': resp, "index": index, "size": size, "total": counts, "pages": page})


@api_routes.route("/roles/all", methods=["GET"])
@certification(auth=True, role=None)
def func_roles_all_get_api():
    """
    获取全部角色, 添加用户时候绑定角色
    http://127.0.0.1:8080/api/roles/all
    Content-Type=application/x-www-form-urlencoded
    methods=["GET"]
    {
    }
    :return:
        {'status': 200, 'data': "data", }
    ---
    tags:
      - 角色管理
    """
    data: List[Rs] = g.session.query(Rs).order_by(desc(Rs.id)).all()
    resp: list = []
    for index0, role in enumerate(data):
        temp = json.loads(role.__repr__())
        del temp["sidebars"]
        resp.append(copy.deepcopy(temp))
    return jsonify({'status': 200, 'data': resp})


@api_routes.route("/roles", methods=["PUT"])
@certification(auth=True, role="admin")
def func_roles_put_api():
    """
    更新角色API接口信息， root admin operation 角色无法更新, 需要角色验证
    http://127.0.0.1:8080/api/roles
    Content-Type=application/json
    methods=["PUT"]
    {
    role_id         int    *** 角色ID, 数据库的，前端不用管
    role:           string      角色名称
    describe:       string      角色描述
    sidebars        list[json]  数据格式： /api/sidebar GET 返回数据格式，属性不能少，只改allow值
    }
    :return:
        {'status': 40001, 'msg': "根据role_id没有找到角色"}
        {'status': 40002, 'msg': "这个角色已经存在"}
        {'status': 40003, 'msg': "这个角色描述已经存在"}
        {'status': 40004, 'msg': "系统自带角色无法更新"}
        {'status': 200, "msg": "角色更新成功"}
    ---
    tags:
      - 角色管理
    """
    data: dict = request.get_json()
    role_id: Union[int, None] = data.get("role_id")
    describe: Union[str, None] = data.get("describe")
    role: Union[str, None] = data.get("role")
    sidebar: Union[List[dict], None] = data.get("sidebars")

    if not all([role_id]):
        abort(400)

    role0: Union[Rs, None] = g.session.query(Rs).filter(Rs.id == role_id).first()
    if role0 is None:
        return jsonify({'status': 40001, 'msg': "根据role_id没有找到角色"})

    role1: Union[Rs, None] = g.session.query(Rs).filter(and_(Rs.id != role_id, Rs.role == role)).first()
    if role1 is not None:
        return jsonify({'status': 40002, 'msg': "这个角色已经存在"})

    role2: Union[Rs, None] = g.session.query(Rs).filter(and_(Rs.id != role_id, Rs.describe == describe)).first()
    if role2 is not None:
        return jsonify({'status': 40003, 'msg': "这个角色描述已经存在"})

    if role0.role in ["admin"]:
        return jsonify({'status': 40004, 'msg': "系统自带角色无法更新"})

    log_pram: dict = {
        "role": role,
        "describe": describe,
        "sidebars": sidebars
    }
    context_logs(name="更新角色", obsolescence=role0.__repr__(), data=str(log_pram))

    role0.role = role if (role and len(role) != 0) else role0.role
    role0.describe = describe if (describe and len(describe) != 0) else role0.describe

    if sidebar is not None and isinstance(sidebar, list):
        mark: dict = {}
        for index2, itr2 in enumerate(sidebar):
            mark2: Union[str, None] = itr2.get("mark")
            allow2: Union[bool, None] = itr2.get("allow")
            children: List[dict] = itr2.get("children")
            if allow2 is True and len(children) == 0:
                mark[mark2] = allow2
            else:
                for index22, itr22 in enumerate(children):
                    mark22: str = itr22.get("mark")
                    allow22: bool = itr22.get("allow")
                    if allow22 is True:
                        mark[mark22] = allow22

        if len(mark) != 0:
            role0.sidebars = json.dumps(mark)
    g.session.commit()
    return jsonify({'status': 200, "msg": "角色更新成功"})


@api_routes.route("/roles", methods=["DELETE"])
@certification(auth=True, role="admin")
def func_roles_delete_api():
    """
    根据role ID 删除角色， root admin operation 角色无法删除, 需要角色验证
    http://127.0.0.1:8080/api/roles
    Content-Type=application/json
    methods=["DELETE"]
    {
    "role_id"   int     ***   role ID
    }
    :return:
        {'status': 40001, 'msg': "根据role_id没有找到角色"}
        {'status': 40002, 'msg': "系统自带角色禁止删除"}
        {'status': 40003, 'msg': "这个角色已经被用户使用， 无法删除"}
        {'status': 200, "msg": "删除角色成功"}
    ---
    tags:
      - 角色管理
    """
    data: dict = request.get_json()
    role_id: str = data.get("role_id")
    if role_id is None:
        abort(400)
    role: Union[Rs, None] = g.session.query(Rs).filter(Rs.id == role_id).first()
    if role is None:
        return jsonify({'status': 40001, 'msg': "根据role_id没有找到角色"})

    if role.role in ["admin"]:
        return jsonify({'status': 40002, 'msg': "系统自带角色禁止删除"})

    users: Union[Us, None] = g.session.query(Us).filter(Us.role_id == role_id).first()
    if users is not None:
        return jsonify({'status': 40003, 'msg': "这个角色已经被用户使用，无法删除"})

    context_logs(name="删除角色", obsolescence=role.__repr__(), data=str({"role_id": role_id}))

    g.session.query(Rs).filter(Rs.id == role_id).delete()
    g.session.commit()
    return jsonify({'status': 200, "msg": "删除角色成功"})
